#pragma once

#include <algorithm/analytical_model/Constants.h>
#include <algorithm/analytical_model/algorithm/cuda/inter_op/Data.h>

#include <memory>

namespace solar::dnn
{
    struct UNIZAR2Output;
}

namespace solar::cuda
{
    class ConvolutionMethod
    {
        public:
            /// @brief 圆柱形接收器 + 矩形定日镜
            ConvolutionMethod(float3* helio_verts, float3 helio_normal, float3 helio_pos,
                              float3 recv_pos, float3 helio_size, float3 recv_size,
                              float3 focus_center, int2 helio_row_col, int2 recv_row_col,
                              bool* d_micro_sb,
                              ConvolutionModelType mode = ConvolutionModelType::kUNIZAR,
                              float* d_array = nullptr, cudaStream_t stream = nullptr);
            /// @brief 矩形接收器 + 矩形定日镜
            ConvolutionMethod(float3* helio_verts, float3 helio_normal, float3 helio_position,
                              float3 focus_center, int2 helio_row_col, int2 recv_row_col,
                              float3* recv_verts, float3 recv_normal, bool* d_micro_sb,
                              float* d_array = nullptr, cudaStream_t stream = nullptr);

            /// @brief 圆柱形接收器 + 矩形定日镜（整个镜场）
            /// @param d_image_plane_xyz_axes 每个定日镜的成像平面的xyz轴
            /// @param d_helio_verts 整个镜场的定日镜顶点的世界坐标系坐标（每个定日镜4个顶点）
            /// @param d_micro_sb 阴影遮挡计算结果（BitMask）
            /// @param d_flux_params 整个镜场的定日镜的参数（sigma1, sigma2, peak）
            /// @param d_focus_centers 定日镜聚焦中心
            /// @param num_helios 定日镜个数
            /// @param recv_size 圆柱形接收器尺寸（半径，高度，ignore）
            /// @param recv_pos 圆柱形接收器中心的世界坐标系坐标
            /// @param helio_row_col 定日镜划分（像素）
            /// @param recv_row_col 接收器划分（像素）
            /// @param mode 卷积模型的类型
            /// @param d_array 结果数组
            /// @param stream CUDA Stream
            ConvolutionMethod(float3* d_image_plane_xyz_axes, float3* d_helio_verts,
                              bool* d_micro_sb, bool* d_micro_sb_per_row, float3* d_flux_params,
                              float3* d_focus_centers, std::size_t num_helios, float3 recv_size,
                              float3 recv_pos_center, int2 helio_row_col, int2 recv_row_col,
                              ConvolutionModelType mode = ConvolutionModelType::kUNIZAR,
                              float* d_array = nullptr, cudaStream_t stream = nullptr);

            /// @brief 圆柱形接收器 + 矩形定日镜（整个镜场）
            /// @param d_image_plane_xyz_axes 每个定日镜的成像平面的xyz轴
            /// @param d_helio_verts 整个镜场的定日镜顶点的世界坐标系坐标（每个定日镜4个顶点）
            /// @param d_micro_sb 阴影遮挡计算结果（BitMask）
            /// @param d_model_outputs 神经网络输出数组
            /// @param d_focus_centers 定日镜聚焦中心
            /// @param num_helios 定日镜个数
            /// @param recv_size 圆柱形接收器尺寸（半径，高度，ignore）
            /// @param recv_pos_center 圆柱形接收器中心的世界坐标系坐标
            /// @param helio_row_col 定日镜划分（像素）
            /// @param recv_row_col 接收器划分（像素）
            /// @param mode 卷积模型的类型
            /// @param d_array 结果数组
            /// @param stream CUDA Stream
            ConvolutionMethod(float3* d_image_plane_xyz_axes, float3* d_helio_verts,
                              bool* d_micro_sb, bool* d_micro_sb_per_row,
                              ::solar::dnn::UNIZAR2Output* d_model_outputs, float3* d_focus_centers,
                              std::size_t num_helios, float3 recv_size, float3 recv_pos_center,
                              int2 helio_row_col, int2 recv_row_col,
                              ConvolutionModelType mode = ConvolutionModelType::kUNIZAR,
                              float* d_array = nullptr, cudaStream_t stream = nullptr);

            ~ConvolutionMethod();

            auto loadGlParam(int n = 10) -> bool;
            /// @brief 绘制圆柱形接收器上的通量图
            void drawFluxMapCylinder();
            void drawFluxMapCylinderFast();
            /// @brief 绘制平面接收器上的通量图
            void drawFluxMap();
            void drawFluxMapFast();
            void setCudaStream(const cudaStream_t& stream);

            // 子定日镜有没有被阴影遮挡，记录全镜场所有镜子的子定日镜
            bool* d_micro_sb_;

            // 卷积模型类型
            ConvolutionModelType mode_;

            // 计算结果
            float* d_array_;
            // gl 参数s
            // float* h_gl_params_;
            std::shared_ptr<float[]> h_gl_params_;
            float* d_gl_params_ = nullptr;
            // 计算参数
            float sigma1_ = 0.0F;
            float sigma2_ = 0.0F;
            float flux_param_ = 0.0F;
            float x3_ = 0.0F;
            float x0_ = 0.0F;
            float y1_ = 0.0F;
            float y0_ = 0.0F;
            // 接收器参数
            float3 recv_pos_;
            float3 recv_size_;

            // 镜场信息
            float3 helio_size_;
            float3 helio_normal_;
            float3 helio_vertices_[4];
            float3 recv_vertices_[4];
            float3 focus_center_;
            float3 helio_pos_;
            // 平面接收器的法向，圆柱形接收器不用指定
            float3 plane_normal_;
            // float helio_reflectivity_ = 0.88;
            // float DNI_ = 1000.0f;
            int2 recv_row_col_;
            int2 helio_row_col_;
            int helio_id_;

            cudaStream_t stream_ = nullptr;
            bool external_stream_ = false;
            bool external_d_array_ = false;
            bool external_heliostat_projection_pos_ = false;

        private:
            // void checkModelTypeAndHeliostatType();
            void setHelioVerts(float3* const helio_vertices);
            // 高斯勒让德求解在中心处的积分值
            auto intCauchyPeak(const float3& x_axis, const float3& y_axis,
                               const float3* const interv, const float& s,
                               const float& area) const -> float;
            auto peekFitting(float peak, float3 x_axis, float3 y_axis, float3 interv[3],
                             float area) -> float;
    };
} // namespace solar::cuda
